Rutvij's Odyssey

Life of a Developer and Technologies he plays with

Playframework issue with OAuth request with query parameters

leave a comment »

I am playing with playframework and building sample application with LinkedIn. I am using awesome secure social play plugin to authenticate users to LinkedIn.

SecureSocial is great framework providing support for OAuth 1 & OAuth 2 and integrate easily in play.

My use case was simple, once user logged in to app ( LinkedIn Oauth 1.0), application makes call to retrieve user’s connections using Linkedin API.


@SecureSocial.SecuredAction
public static Result index() {
Identity user = (Identity) ctx().args.get(SecureSocial.USER_KEY);
Option<OAuth1Info> info = user.oAuth1Info();
OAuth1Info oAuth1Info = info.get();
String consumerKey = Play.application().configuration()
.getString("securesocial.linkedin.consumerKey");
String consumerSecret = Play.application().configuration()
.getString("securesocial.linkedin.consumerSecret");
// Getting URL from conf
String url = Play.application().configuration()
.getString("myapp.profile.url");
ConsumerKey key = new ConsumerKey(consumerKey, consumerSecret);
RequestToken token = new RequestToken(oAuth1Info.token(),
oAuth1Info.secret());
// Using BuiltIn OAuthCalculator to generate signature for request
OAuthCalculator calc = new OAuthCalculator(key, token);
String response = WS.url(url).setHeader("x-li-format", "json")
.sign(calc).get().get().getBody();
return ok(response);
}

I had configured “myapp.profile.url to use following url  http://api.linkedin.com/v1/people/~/connections

It worked fine and returned all the connections,but when I modified url to use query parameters to do people search : http://api.linkedin.com/v1/people-search?last-name=shah
I got following error :

{
"errorCode": 0,
"message": "[unauthorized]. OAU:***************************************",
"requestId": "LST33GHM3E",
"status": 401,
"timestamp": 1371245720144
}

To debug this I put TCPMon proxy between Play and linkedin and found WS.url is ignoring query params passed in url.

I changed code  to add query parameter this way : .setQueryParameter("last-name", "shah") 

But this has not changed the response and returned unauthorized error.

It took me while to realize that Playframework’s OAuthCalculator is not generating signature correctly and little googling confirmed it https://github.com/playframework/Play20/issues/1159

Now I have chicken & egg problem, WS.url does not take querystring and using .setQueryParameter not getting included in generated signature.

I started digging into Play code and found that Play’s WS.url APIs are wrapper around Ning Aync http client.

I refactored code to directly using ning’s http client along with its OAuth calculator and it worked fine :


@SecureSocial.SecuredAction
public static Result index() {
Identity user = (Identity) ctx().args.get(SecureSocial.USER_KEY);
Option<OAuth1Info> info = user.oAuth1Info();
OAuth1Info oAuth1Info = info.get();
String consumerKey = Play.application().configuration()
.getString("securesocial.linkedin.consumerKey");
String consumerSecret = Play.application().configuration()
.getString("securesocial.linkedin.consumerSecret");
String url = "http://api.linkedin.com/v1/people-search&quot;;
/*** Modified OAuth Request code to use Ning's AyncHttpClient ***/
OAuthSignatureCalculator calc = null;
com.ning.http.client.oauth.ConsumerKey consumerAuth1 = new com.ning.http.client.oauth.ConsumerKey(
consumerKey, consumerSecret);
com.ning.http.client.oauth.RequestToken userAuth1 = new com.ning.http.client.oauth.RequestToken(
oAuth1Info.token(), oAuth1Info.secret());
calc = new OAuthSignatureCalculator(consumerAuth1, userAuth1);
AsyncHttpClient client = new AsyncHttpClient();
client.setSignatureCalculator(calc);
try {
Future<Response> f = client.prepareGet(url)
.addQueryParameter("last-name", "shah")
.addHeader("x-li-format", "json").execute();
String responseBody = f.get().getResponseBody();
return ok(index.render(responseBody));
} catch (Exception e) {
logger.error("Exception while getting people" + e, e);
}
return internalServerError("Error");
}

TLDR 😉

Playframeork 2.1.0 OAuthCalculator has bug so it does not work with url contains queryString, use Ning’s AyncHttpClient instead.

Written by rutvijshah

June 14, 2013 at 3:05 pm

Sublime Text 2 JSHint Plugin issue on windows

leave a comment »

Sublime Text 2 is my favorite editor now a days. It has nice look and feel and great features.

I was trying to use its Plugin for integration of JSHint. I read Pre requistes and followed every steps but I was getting following error every time I do build (to run JSHint) .

node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Cannot find module 'PATH\AppData\Roaming\Sublime Text 2\Packages\JSHint\scripts\run.js'
at Function._resolveFilename (module.js:332:11)
at Function._load (module.js:279:25)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:40)
[Finished]

I googled it to see if anyone has workaround,but I could not find one.  Finally I am able to solve it with following steps:

  1. Go to directory of JShint under packages for example …’PATH\AppData\Roaming\Sublime Text 2\Packages\JSHint
  2. Get   both the js files from https://github.com/victorporof/Sublime-JSHint/tree/master/scripts to scripts directory
  3. Restart Sublime and run JSHint it will work

Written by rutvijshah

March 25, 2012 at 10:16 pm

Spring Roo AuditTimestamp Addon

leave a comment »

Spring Roo is developer tool which helps to do rapid development in java/j2ee.

Spring Roo is inspired from Rails framework, and has cool features for Rapid development.

I have been developing applications using Spring roo and quite happy with it. It does has some cons which I will discuss in my next posts.

Recently I have developed Spring roo Addon and contributed to Spring Roo.

This projects is hosted on Google Projects : http://code.google.com/p/spring-roo-addon-audit-timestamp/ for more information please refer proejct’s wiki page.

Written by rutvijshah

August 7, 2011 at 11:38 am

Liferay Cache

with 4 comments

Leveraging  Liferay Cache to Improve performance :

Liferay provides out of box Cache MultiVMPool, which can be used by portlets to cache results of heavy network calls  i.e. web services.

MultiVMPool  Cache is very easy to use and yet powerful enough to work in clustered environment. Unfortunately there is no official documentation for MultiVMPool, which describes how it works and how it can be leverage by portlets.

What is MultiVMPool Cache ?

    • Out of Box Cache from Liferay :  No additional configuration infrastructure needed.
    • Wrapper around EHCache : As powerful as EHCache
    • Clustered Cache
    • JVM Level Cache: Object cached by one WAR will be available to other WARs on same JVM.

How to Use :-

    • MutliVMPoolUtil : Utility class provides methods to access MultiVMPool
      http://docs.liferay.com/portal/5.1/javadocs/portal-kernel/com/liferay/portal/kernel/cache/MultiVMPoolUtil.html
    • Common Usage :
      Using MultiVMPoolUtil : new cache will be dynamically created if not exits.
      Following methods shows basic usage :
      name= Cache Name
      key=Key of Cache Entry
      obj=Object to be Cached.

      Put Obeject in Cache
      put(java.lang.String name, java.lang.String key, java.io.Serializable obj)

      Get Object from Cache

      get(java.lang.String name, java.lang.String key)

      Clear Cache

      clear
      (java.lang.String name)Remove Object from Cache
      remove(java.lang.String name, java.lang.String key)

      Please note here that Liferay MutliVMPoolUtil provides overloaded method to put Normal object (i.e non serialized) also. But in Clustered environment make sure to use Serialized object which can be copied to other caches over wire.

      Clustered Cache needs to enable from portal.properties
      ehcache.multi.vm.config.location=/ehcache/liferay-multi-vm-clustered.xml

Pros:

    • Easy to Use
    • No configuration required from portlet
    • Clustered Cache

Cons:

    • Use Default settings for Cache created. No API to set different  timeToLive,timeToIdle
      settings for the cache.
    • To change default Cache settings only done using  EXT environment.

Written by rutvijshah

February 27, 2010 at 1:23 pm

Workaround : Making setPortletMode working in Liferay

with 3 comments

In Liferay  set portlet mode from processAction() is  not setting Portlet Mode properly.

There is a bug filed on Liferay JIRA ( http://issues.liferay.com/browse/LPS-114 ).

Its use case is  as below described in Liferay JIRA:

1. process a portlet action and set the portlets window state and portlet mode in the portlets processAction method
2. When the portlet is rendered for the first time directly after the state/mode change, then the portlet seems to be in the correct state and portlet mode. (getPortletMode / getWindowState are equal to the new settings )
3. Afterwards – when the page is rendered again – then the portlet falls back to its previous window state and portlet mode (f.e. when you make a round trip to another tab)

A patch is provided for this bug ,but still not fixed in Liferay 5.2.3. Also the patch will be useful for team working with EXT environment where they can directly apply  patch to change Liferay source code.

I found one workaround which will work without changing source code . I have tested it on Tomcat 5.5, Tomcat 6.1, Websphere 6.1 with Liferay 5.2.3 and should work for earlier versions also.

Solution Summary :

It seems Liferay is tracking mode using http parameters. We need to append those parameters in page. Need to add few Query String parameters to Portal Page which contains the portlet.

p_p_id=<PortletId>&p_p_lifecycle=0&p_p_state=normal&p_p_mode=view

<PortletId> : It is the portlet Id for target Portlet.

Step by Step Solution:

  1. Go to Portlet Preferences.
  2. You can see default link “ Return to Full Page “ . Right click on it. It will popup browser menu copy the link address.
  3. Copy it in to text editor, for my portlet it is :
    http://localhost:8080/web/test/mychamp?p_p_id=MyChamp_WAR_MyChamp&p_p_lifecycle=0&p_p_state=normal&p_p_mode=view&p_p_col_id=column-1&p_p_col_count=1
  4. We need only following part for my portlet: p_p_id=MyChamp_WAR_MyChamp&p_p_lifecycle=0&p_p_state=normal&p_p_mode=view
    copy it,according to your portlet/war name it will be different.
  5. Go To Manage pages menu.
  6. Select the page which contains the target portlet.  In the page’s Query String  paste the filtered query String.
  7. Save changes.
  8. Come back to portlet and retest after saving preferences , even if you come from different page it will work as per expected.

Written by rutvijshah

January 10, 2010 at 1:09 pm

Liferay Session Sharing : Made Easy

with 5 comments

Inter portlet coummunication is made easy with JSR 286. But all IPC (Inter-Portlet Communications)  mechanisms (public render parameters,Events ) is about ACTION-to-VIEW.
  • What I mean by ACTION-to-VIEW is on “action phase” of one portlet information is shared and made available to specific/all portlet’s “view phase”.
  • There are use cases  where we need a IPC mechanism to share information between portlets of different WARs  in VIEW-to-VIEW .It means One portlet will share information from its VIEW phase and will be available to other Portlet in VIEW phase.
By default Each WAR has its own session and will not be shared with other WARs.
Liferay provides a mechanism by which Portlets can share session attributes across WARs.
How to Setup :

1.liferay-portlet.xml
For Portlets who will share (i.e setAttribute() ) session attributes(s) need to add following entry in liferay-portlet.xml

<portlet>...
<private-session-attributes>false</private-session-attributes>
</portlet>

2. Use Namespace prefix to Share/Get shared session attribute:

By default “LIFERAY_SHARED_”  prefix is used for sharing session attribute to other WARs.  It can be customized with in portal.properties ‘s session.shared.attributes value.
portletSession.setAttribute( "LIFERAY_SHARED_mySpecialVar",value,PortletSession.APPLICATION_SCOPE);
Other portlet(s)  in different WAR  can access it :
portletSession.getAttribute( "LIFERAY_SHARED_mySpecialVar",PortletSession.APPLICATION_SCOPE);
3. Caveat :

Using Liferay’s custom Session Sharing mechanism Portlet can share session with other Portlet in Different WAR but not with the Servlet in Different WAR.
It can be shared with Servlet ( of Different WAR) via Portlet of that WAR.

How to Share with Servlet of Other WAR :-
Portlet One :
portletSession.setAttribute( "LIFERAY_SHARED_mySpecialVar",value,
PortletSession.APPLICATION_SCOPE);
Portlet Two:

Object value=  portletSession.getAttribute
( "LIFERAY_SHARED_mySpecialVar",PortletSession.APPLICATION_SCOPE);//getting shared value
portletSession.setAttribute
( "mySpecialVar",value,PortletSession.APPLICATION_SCOPE);//setting to 'local' session

Servlet Two:

request.getSession().getAttribute("mySpecialVar");

Developer has to be aware while sharing/accessing “shared” session attributes, also note that if prefix is customized need to change the source code.
I have developed a Utility which can make Liferay Session sharing easier for developers.
Its taking care of customized prefix also and provides neat way to set/access shared session attributes.
/*****
<pre>* RUTVIJ SHAH MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. RUTVIJ SHAH SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
* THIS SOFTWARE IS IN AS-IS FORM, YOU ARE FREE TO RE-DISTRIBUTE/CHANGE WITHOUT ANY NOTIFICATION TO AUTHOR.
******/

package myapp.liferayImpl.session.util;

import com.liferay.portal.kernel.util.PropsUtil;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;

/**
* @author Rutvij Shah ( rutvij.shah@yahoo.com )
* LiferaySessionUtil provides helper methods to share your Session attributes
* across WARs.
*
*/
public class LiferaySessionUtil {
/***
* This prefix is used by Liferay Portal to detect Session Attributes
* for sharing betweeen WARs.
*/

private static final String LIFERAY_SHARED_SESSION_PREFIX=getSharedSessionPrefix();
private static final String LIFERAY_SHARED_SESSION_PREFIX_DEFAULT="LIFERAY_SHARED_";
/****
* It stores attribute as 'Shared' Attribute and will be available to other
* portlets in different WARs.
*
* Attributes shared by this method will be available to only Portlets,
* not other Web components i.e Servlet.
*
* @param key session Key to store value
* @param value
* @param request PortletRequest
*/
public static final void setGlobalSessionAttribute(String key,Object value,PortletRequest request){
if(key!=null){
String globalKey=getGlobalKey(key);
PortletSession portletSession=request.getPortletSession();
portletSession.setAttribute(globalKey,value,PortletSession.APPLICATION_SCOPE);
}
}
/****
*
* It provides access to get shared session attributes from other portles
* from diffrent WARs.
*
* @param key
* @param request
* @return
*/
public static final Object getGlobalSessionAttribute(String key,PortletRequest request){
Object value=null;
if(key!=null){
String globalKey=getGlobalKey(key);
PortletSession portletSession=request.getPortletSession();
value=portletSession.getAttribute(globalKey,PortletSession.APPLICATION_SCOPE);
}
return value;
}

/******
*
* It provides a way to further share 'Shared'Session Attributes from
* Portlet to other Web Components i.e Servlets .
*
* @param key
* @param request
*/
public static final void shareGlobalSessionAttribute(String key,PortletRequest request){
if(key!=null){
Object value=getGlobalSessionAttribute(key, request);
PortletSession portletSession=request.getPortletSession();
portletSession.setAttribute(key,value,PortletSession.APPLICATION_SCOPE);
}
}

/***
* Helper method to generate Global key using Liferay shared prefix
* @param key
* @return
*/
private static final String getGlobalKey(String key){
return LIFERAY_SHARED_SESSION_PREFIX+key;
}

/********
* Helper method to get Liferay's Session Sharing prefix
* Useful when Liferay is customized to use different prefix other than Default
*
* @return
*/
private static final String getSharedSessionPrefix(){
String value=null;
try {
/**
* Getting value from portal.properties
*/
value = PropsUtil.get("session.shared.attributes");
} catch (Exception ex) {
Logger.getLogger(LiferaySessionUtil.class.getName()).log(Level.SEVERE, null, ex);
}

if(value !=null){
if(value.contains(LIFERAY_SHARED_SESSION_PREFIX_DEFAULT)){
//if default prefix is configured use it
value=LIFERAY_SHARED_SESSION_PREFIX_DEFAULT;
}else{
//use first one from the list of prefix configured
value=value.split(",")[0];
}
}else{
/**
* If none of the value configured use default one
* Note: Session Sharing may not work as none of the value configured.
*/
value=LIFERAY_SHARED_SESSION_PREFIX_DEFAULT;
}
return value;
}

}
Using this Util class  for same use case :
Portlet One :
LiferaySessionUtil.setGlobalSessionAttribute
("mySpecialVar",value, portletRequest); //adding 'proper' prefix will be taken care by Utility
PortletTwo:

Object value=  LiferaySessionUtil.getGlobalSessionAttribute
("mySpecialVar", portletRequest); //to get value for portlet
LiferaySessionUtil.shareGlobalSessionAttribute
("mySpecialVar", portletRequest);//to share value to servlets

As you can see if Portlet Two only need to share it with servlet no need of first line.

Servlet Two:
 request.getSession().getAttribute("mySpecialVar");

Feel free to share your comments on this. You can download LiferaySessionUtil.java  from here :  LiferaySessionUtil


Written by rutvijshah

December 13, 2009 at 7:54 pm

User specific Preferences in Liferay

with 6 comments

As per JSR 168 Specificaiton Portlet Preferences are user specific and may be shared across portlets/pages ( NOT Mandatory: config/edit_shared modes)  which depends on portlet container.

If you have Websphere Portlet development experience you will wonder why preferences are not ‘user specific’  in liferay.

In this post I will explain how to solve this mystery and make your user specific preferences work in Liferay too.

Preferences in this example :
Portlet shows two  preference values  in VIEW mode JSP:  A. Sets dynamically by API B. From portlet.xml.
Edit Mode shows and allow to update preferences.
processAction stores updated  preferences.

Really simple use  isn’t it ?

Expected Behavior:
When user Bob logs in to portal and set his preferences, he can see them in VIEW mode. So preferences are personalized only for Bob. When Alice/another user logs in to Portal she can set her preferences which is only for her, no other user can see.

In Websphere portal: As per Expected.

In Liferay portal: When Bob logs in and set his preferences and it will be set for Alice and David too .i.e when Alice logs in to portal she can see preferences values set by Bob. If she too updates, it overwrites value set by Bob.

I was wondering  why its happening like this…because as  per JSR if user sets Preferences in EDIT/VIEW/HELP  mode it is user specific only.

Solution : Liferay supports  great level of customization for preferences (I will explain it  in details in my future posts).

But by default  Liferay sets  some customized levels for preferences  ‘ON’.

So in order to make  preferences  user specific in liferay, add following entries to liferay-portlet.xml :

<portlet>
....
<preferences-unique-per-layout>false</preferences-unique-per-layout>
<preferences-owned-by-group>false</preferences-owned-by-group>
....
</portlet>

Do these changes and redeploy portlet, now Bob’s preferences are for Bob only !!!

Written by rutvijshah

December 6, 2009 at 3:34 pm

Useful Eclipse Shortcuts for Java Developer

leave a comment »

Eclilpse is one of the most popular IDE for JAVA based development projects. As we know every technologies and tools comes with its own learning curve. Althaugh eclilpse is very easy to use but still lot  of the developers are not using it at its fullest capacity.

Here  in this post I will  show some very useful Eclipse shortcuts which will be useful for you in your day to day development.

  1. Get rid of  manual Import statements  : Organize Imports ( Ctrl+Shift+O)
    After  you write a line of your code you may need to Impot classed used in your code.Otherwise eclipse will show  errors as you can see in this image. Organize Import will import classes if found from class path of your project.

  2. Quickly Go to File : Open Resource ( Ctrl+Shift+R)
    Project we have several packages, in order to go to the particular file developer need to traverse to file through packages/folders in Navigator /Package view.For  example I am looking for BaseModelImpl.java file  instead of going through all packages/folders
    Do : Open Resource ( Ctrl + Shift + R  ) and type BaseImpl it will show all files starts with BaseImpl you can select the file you need and  press OK to open. It supports  RegEx so you can type like Ba*Im*.java also to filter your search.It can locate any file in your project not limited to .java files.

  3. Quickly locate JAR which contains ‘the class’Open Type ( Ctrl+Shift+T)
    Several times I need to  know which particular  JAR contains the class I am interested in. For Example  I have couple of projects in workspace and I copy paste few lines from other project.Its giving errors as Eclipse not able to resolve classes. As its working in other projects,  I need to know which JAR file this class contains and I need to copy that jar file to my project and/or set in classpath.

  4. Jump to Last Edit Location : (Ctrl+Q)
    Working with multiple source files is reality of development . When you are working with multiple source files and need to know in which file you made last changes you can easily Jump to last Edit Location using ( Ctrl+ Q).
  5. Locate where this method is reffered in projects : (Ctrl+Shift+G) (Quick Search)
    In order to know where this particular method/variable is reffered not only in this project but other projects of workspace also.
    Select method in Editor and do Ctrl+Shift+G. In search view Eclipse will search its references in all projects in current workspace.

Written by rutvijshah

December 5, 2009 at 5:14 pm

Posted in Eclipse IDE

Tagged with , ,

Hello world!

leave a comment »

Hello world !!! I will use this blog medium to share my thoughts and ideas about Technologies and my life as a Developer.

I am passionate about Java and Java related technologies, working as Software Consultant.

 

Written by rutvijshah

November 29, 2009 at 6:41 am

Posted in Uncategorized